﻿using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using HandyControl.Controls;
using HandyControl.Tools.Extension;
using HardToolApp.Model;
using HardToolApp.Properties;
using HardToolApp.Tool;
using HardToolApp.View;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OxyPlot;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Shapes;

namespace HardToolApp.ViewModel
{
    [ViewModelHelper("发送列表", typeof(Order), typeof(OrderModel), Sort = 8)]
    public class OrderVM:PeripheralVM
    {
        ResourceDictionary myResourceDictionary = new ResourceDictionary
        {
            Source = new Uri("pack://application:,,,/HandyControl;component/Themes/Theme.xaml", UriKind.RelativeOrAbsolute) // 指定样式文件的路径
        };
        ObservableCollection<OrderModel> models = new ObservableCollection<OrderModel>();
        ObservableCollection<OrderModel> _orders;
        ObservableCollection<CmdsModel> _cmds = new ObservableCollection<CmdsModel>();
        Style _btnStyle;
        string _info;
        string _btnStr;
        bool _isPreShow = false;
        CmdsModel _selCmd;

        public CmdsModel selCmd { get => _selCmd; set { SetProperty(ref _selCmd, value); } }
        public bool IsPreShow { get => _isPreShow; set { SetProperty(ref _isPreShow, value); } }
        public ObservableCollection<CmdsModel> cmds { get => _cmds; set { SetProperty(ref _cmds, value); } }
        public ObservableCollection<OrderModel> orders { get { return _orders; } set { SetProperty(ref _orders, value); } }
        public Style btnStyle { get { return _btnStyle; } set { SetProperty(ref _btnStyle, value); } }
        public string info { get { return _info; } set { SetProperty(ref _info, value); } }
        public string btnStr { get { return _btnStr; } set { SetProperty(ref _btnStr, value); } }
        public RelayCommand newCmd { get; set; }
        public RelayCommand runCmd { get; set; }
        public RelayCommand preCmd { get; set; }
        public RelayCommand saveCmd { get; set; }
        public RelayCommand<CmdsModel> deletePreCmd { get; set; }
        public RelayCommand<object> loadCmd { get; set; }
        public RelayCommand<OrderModel> deleteItem { get; set; }

        private int indexNow = 0;
        private int retryTick = 0;
        public OrderVM() {
            orders = new ObservableCollection<OrderModel>();
            newCmd = new RelayCommand(NewCmdDeal);
            runCmd = new RelayCommand(RunCmdDeal);
            preCmd = new RelayCommand(PreCmdDeal);
            saveCmd = new RelayCommand(SaveCmdDeal);
            deleteItem = new RelayCommand<OrderModel>(DeleteItemDeal);
            loadCmd = new RelayCommand<object>(LoadPreDeal);
            deletePreCmd = new RelayCommand<CmdsModel>(DeletePreCmd);
            //WeakReferenceMessenger.Default.Register<byte[]>(this, Rec);
            btnStyle = myResourceDictionary["ButtonSuccess"] as Style;
            btnStr = "运行";
            cmds = Presupposition.NeedNewPresupposition();
        }

        private void LoadPreDeal(object t)
        {
            try
            {
               
                orders = Presupposition.Load(selCmd.Path);
                IsPreShow = false;
            }
            catch
            {

            }
            
        }
        private void DeleteItemDeal(OrderModel t)
        {
            if (HandyControl.Controls.MessageBox.Show("是否删除", button: MessageBoxButton.OKCancel) == MessageBoxResult.OK)
            {
                orders.Remove(t);
            }

        }
        private async void SaveCmdDeal()
        {
            string Name = await Dialog.Show<InteractiveDialog>()
                .GetResultAsync<string>();
            if (string.IsNullOrEmpty(Name)) 
            {
                return;
            }
            Presupposition.SaveCmds(orders, cmds, Name);
            Growl.Success("保存成功");
        }

        private void DeletePreCmd(CmdsModel p)
        {
            if (HandyControl.Controls.MessageBox.Show("是否删除", button: MessageBoxButton.OKCancel) == MessageBoxResult.OK)
            {
                Presupposition.Delete(p,cmds);
            }
        }

        private void PreCmdDeal()
        {
            IsPreShow = true;
            
        }
        private void NewCmdDeal()
        {
            orders.Add(new OrderModel() { CmdType = CommCmd.COMM_UART });
        }
        private void UpdateClass(Peripheral baseClass)
        {
            USBInfoVM.VMHelper helper = (USBInfoVM.VMHelper)USBInfoVM.peripheralList[baseClass.GetType()];
            helper.VM.Send(baseClass);
            //switch (baseClass.commType)
            //{
            //    case CommCmd.COMM_UART:
            //        WeakReferenceMessenger.Default.Send(baseClass as UartModel);
            //        break;
            //    case CommCmd.COMM_IIC_SLAVE:
            //        WeakReferenceMessenger.Default.Send(baseClass as IICSlaveModel);
            //        break;
            //    case CommCmd.COMM_IIC_MASTER:
            //        WeakReferenceMessenger.Default.Send(baseClass as IICMasterModel);
            //        break;
            //    case CommCmd.COMM_SPI_SLAVE:
            //        WeakReferenceMessenger.Default.Send(baseClass as SPISlaveModel);
            //        break;
            //    case CommCmd.COMM_SPI_MASTER:
            //        WeakReferenceMessenger.Default.Send(baseClass as SPIMasterModel);
            //        break;
            //    case CommCmd.COMM_GPIO:
            //        WeakReferenceMessenger.Default.Send(baseClass as GpioModel.GPIO);
            //        break;
            //    case CommCmd.COMM_PWM:
            //        WeakReferenceMessenger.Default.Send(baseClass as PwmModel.PWM);
            //        break;
            //}
            info += baseClass.ToString();
        }
        private void RunCmdDeal()
        {
            if(btnStr.Equals("运行"))
            {
                if(orders.Count > 0)
                {
                    models.Clear();
                    info = "";
                    foreach(OrderModel order in orders) 
                    {
                        models.Add(order);
                    }
                    btnStr = "停止";
                    indexNow = 0;
                    retryTick = 0;
                    btnStyle = myResourceDictionary["ButtonDanger"] as Style;
                    UpdateClass(models[0].cmd);
                }
                
            }
            else
            {
                btnStr = "运行";
                btnStyle = myResourceDictionary["ButtonSuccess"] as Style;
                indexNow = 0;
            }
        }
        #region 接收处理
        [DllImport("msvcrt.dll")]
        private static extern IntPtr memcmp(byte[] b1, byte[] b2, IntPtr count);
        private bool UartDeal(byte[] b)
        {
            UartModel model = models[indexNow].cmd as UartModel;
            switch (b[4])
            {
                case (byte)CommSubCmdUart.COMM_SUB_UART_SET_PARAM:
                case (byte)CommSubCmdUart.COMM_SUB_UART_SEND:
                    info += model.cmdName+" " + Communicate.SubString[b[4]] + " " + EnumExtensions.GetDescription((CommStatus)b[5]) + "\n";
                    if (b[5] == (byte)CommStatus.COM_OK)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                case (byte)CommSubCmdUart.COMM_SUB_UART_REC://数据接收
                    byte[] bArr = new byte[b[2] - 6];
                    byte[] bSrc = Common.String2Byte(model.receiveBytes);

                    b.Skip(5).ToArray().CopyTo(bArr, 0);
                    info += "Uart rec:" + Common.Byte2String(bArr) +"\n";
                    if (bArr.Length != bSrc.Length)
                    {
                        return false;
                    }
                    if(memcmp(bArr,bSrc, new IntPtr(bArr.Length)).ToInt32() == 0)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
            }
            return false;
        }
        private bool SPISlaveDeal(byte[] b)
        {
            switch (b[4])
            {
                case (byte)CommSubCmdSPISlave.COMM_SUB_SPI_SLAVE_SET_PARAM:
                case (byte)CommSubCmdSPISlave.COMM_SUB_SPI_SLAVE_WRITE:
                    info += models[indexNow].cmd.cmdName + " " + Communicate.SubString[b[4]] + " " + EnumExtensions.GetDescription((CommStatus)b[5]) + "\n";
                    if (b[5] == (byte)CommStatus.COM_OK)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                case (byte)CommSubCmdSPISlave.COMM_SUB_SPI_SLAVE_READ://数据接收
                    if (b[5] == (byte)CommStatus.COM_OK)
                    {
                        ((Communicate)models[indexNow].cmd).receiveBytes = Common.Byte2String(b.Skip(6).ToArray(), len: b[2] - 7);
                        info += models[indexNow].cmd.cmdName + "接收到" + ((Communicate)models[indexNow].cmd).receiveBytes + "\n";
                        return true;
                    }
                    else
                    {
                        info += models[indexNow].cmd.cmdName + " " + Communicate.SubString[b[4]] + " " + EnumExtensions.GetDescription((CommStatus)b[5]) + "\n";
                        return false;
                    }
            }

            return false;
        }
        private bool IICSlaveDeal(byte[] b)
        {
            switch (b[4])
            {
                case (byte)CommSubCmdIICSlave.COMM_SUB_IIC_SLAVE_SET_PARAM:
                case (byte)CommSubCmdIICSlave.COMM_SUB_IIC_SLAVE_WRITE:
                    info += models[indexNow].cmd.cmdName + " " + Communicate.SubString[b[4]] + " " + EnumExtensions.GetDescription((CommStatus)b[5]) + "\n";
                    if (b[5] == (byte)CommStatus.COM_OK)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                case (byte)CommSubCmdIICSlave.COMM_SUB_IIC_SLAVE_READ://数据接收
                    if (b[5] == (byte)CommStatus.COM_OK)
                    {
                        ((Communicate)models[indexNow].cmd).receiveBytes = Common.Byte2String(b.Skip(6).ToArray(), len: b[2] - 7);
                        info += models[indexNow].cmd.cmdName + "接收到" + ((Communicate)models[indexNow].cmd).receiveBytes + "\n";
                        return true;
                    }
                    else
                    {
                        info += models[indexNow].cmd.cmdName + " " + Communicate.SubString[b[4]] + " " + EnumExtensions.GetDescription((CommStatus)b[5]) + "\n";
                        return false;
                    }
            }
            return false;
        }
        private bool SPIMasterDeal(byte[] b)
        {
            switch (b[4])
            {
                case (byte)CommSubCmdSPIMaster.COMM_SUB_SPI_MASTER_SET_PARAM:
                case (byte)CommSubCmdSPIMaster.COMM_SUB_SPI_MASTER_WRITE:
                    info += models[indexNow].cmd.cmdName + " " + Communicate.SubString[b[4]] + " " + EnumExtensions.GetDescription((CommStatus)b[5]) + "\n";
                    if (b[5] == (byte)CommStatus.COM_OK)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                case (byte)CommSubCmdSPIMaster.COMM_SUB_SPI_MASTER_READ://数据接收
                    if (b[5] == (byte)CommStatus.COM_OK)
                    {
                        ((Communicate)models[indexNow].cmd).receiveBytes = Common.Byte2String(b.Skip(6).ToArray(), len: b[2] - 7);
                        info += "SPI主机接收:" + ((Communicate)models[indexNow].cmd).receiveBytes;
                        return true;
                    }
                    else
                    {
                        info += models[indexNow].cmd.cmdName + " " + Communicate.SubString[b[4]] + " " + EnumExtensions.GetDescription((CommStatus)b[5]) + "\n";
                        return false;
                    }
                case (byte)CommSubCmdSPIMaster.COMM_SUB_SPI_MASTER_WRITE_READ://数据接收
                    if (b[5] == (byte)CommStatus.COM_OK)
                    {
                        ((Communicate)models[indexNow].cmd).receiveBytes = Common.Byte2String(b.Skip(6).ToArray(), len: b[2] - 7);
                        info += "SPI主机接收:" + ((Communicate)models[indexNow].cmd).receiveBytes;
                        return true;
                    }
                    else
                    {
                        info += models[indexNow].cmd.cmdName + " " + Communicate.SubString[b[4]] + " " + EnumExtensions.GetDescription((CommStatus)b[5]) + "\n";
                        return false;
                    }
            }
            return false;
        }
        private bool IICMasterDeal(byte[] b)
        {
            switch (b[4])
            {
                case (byte)CommSubCmdIICMaster.COMM_SUB_IIC_MASTER_SET_PARAM:
                case (byte)CommSubCmdIICMaster.COMM_SUB_IIC_MASTER_WRITE:
                    info += models[indexNow].cmd.cmdName + " " + Communicate.SubString[b[4]] + " " + EnumExtensions.GetDescription((CommStatus)b[5]) + "\n";
                    if (b[5] == (byte)CommStatus.COM_OK)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                case (byte)CommSubCmdIICMaster.COMM_SUB_IIC_MASTER_READ://数据接收
                    if (b[5] == (byte)CommStatus.COM_OK)
                    {
                        ((Communicate)models[indexNow].cmd).receiveBytes = b[6].ToString("X2") + ':' + Common.Byte2String(b.Skip(7).ToArray(), len: b[2] - 8);
                        info += "IIC主机接收:" + ((Communicate)models[indexNow].cmd).receiveBytes + "\n";
                        return true;
                    }
                    else
                    {
                        info += models[indexNow].cmd.cmdName + " " + Communicate.SubString[b[4]] + " " + EnumExtensions.GetDescription((CommStatus)b[5]) + "\n";
                        return false;
                    }
            }
            return false;
        }
        private bool GPIODeal(byte[] b)
        {
            switch (b[4])
            {
                case (byte)CommSubGPIO.COMM_SUB_GPIO_LEVEL_READ:
                    ((GpioModel.GPIO)(models[indexNow].cmd)).Level = b[7]==1?true:false;
                    info += models[indexNow].cmd.cmdName + " " + Communicate.SubString[b[4]] + " " + EnumExtensions.GetDescription((CommStatus)b[5]) + "\n";
                    if (b[5] == (byte)CommStatus.COM_OK)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                case (byte)CommSubGPIO.COMM_SUB_GPIO_LEVEL_SET:
                case (byte)CommSubGPIO.COMM_SUB_GPIO_PIN_SET:
                
                    info += models[indexNow].cmd.cmdName + " " + Communicate.SubString[b[4]] + " " + EnumExtensions.GetDescription((CommStatus)b[5]) + "\n";
                    if (b[5] == (byte)CommStatus.COM_OK)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                case (byte)CommSubGPIO.COMM_SUB_GPIO_HL_CHANGE:
                    info += models[indexNow].cmd.cmdName + " " + Communicate.SubString[b[4]] + " " + EnumExtensions.GetDescription((CommStatus)b[5]) + "\n";
                    if (((GpioModel.GPIO)(models[indexNow].cmd)).NeedWait == true)
                    {
                        GpioModel.GPIO g = (GpioModel.GPIO)models[indexNow].cmd;
                        Thread.Sleep((g.FirstHoldTime+g.SecondHoldTime)*g.RepeatTimes);
                    }
                    if (b[5] == (byte)CommStatus.COM_OK)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
            }
            return false;
        }
        private bool PWMDeal(byte[] b)
        {
            switch (b[4])
            {
                case (byte)CommSubPWM.COMM_SUB_PWM_SET_PARAM:
                case (byte)CommSubPWM.COMM_SUB_PWM_OPEN_CLOSE:
                    info += models[indexNow].cmd.cmdName + " " + Communicate.SubString[b[4]] + " " + EnumExtensions.GetDescription((CommStatus)b[5]) + "\n";
                    if (b[5] == (byte)CommStatus.COM_OK)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
            }
            return false;
        }
        public override void RecData(object t,byte[] b)
        {
            try
            {
                bool res = false;
                if (b[3] == (byte)CommCmd.COMM_ADC || models.Count == 0 || !btnStr.Equals("停止")) return;
                if (b[3] == (byte)models[indexNow].cmd.commType && b[4] == models[indexNow].cmd.subCmd)
                {
                    switch (b[3])
                    {
                        case (byte)CommCmd.COMM_UART:
                            res = UartDeal(b);
                            break;
                        case (byte)CommCmd.COMM_SPI_SLAVE:
                            res = SPISlaveDeal(b);
                            break;
                        case (byte)CommCmd.COMM_IIC_SLAVE:
                            res = IICSlaveDeal(b);
                            break;
                        case (byte)CommCmd.COMM_SPI_MASTER:
                            res = SPIMasterDeal(b);
                            break;
                        case (byte)CommCmd.COMM_IIC_MASTER:
                            res = IICMasterDeal(b);
                            break;
                        case (byte)CommCmd.COMM_GPIO:
                            res = GPIODeal(b);
                            break;
                        case (byte)CommCmd.COMM_PWM:
                            res = PWMDeal(b);
                            break;
                    }
                    // 发送下一个命令
                    if (res)
                    {
                        indexNow++;
                        if (indexNow >= models.Count)
                        {
                            btnStr = "运行";
                            retryTick = 0;
                            indexNow = 0;
                            btnStyle = myResourceDictionary["ButtonSuccess"] as Style;
                        }
                        else
                        {
                            UpdateClass(models[indexNow].cmd);
                        }
                    }
                    else
                    {
                        // 重新发送当前命令
                        retryTick++;
                        if (retryTick >= 3)// 重发失败重新发送
                        {
                            btnStr = "运行";
                            btnStyle = myResourceDictionary["ButtonSuccess"] as Style;
                            indexNow = 0;
                        }
                        else
                        {
                            UpdateClass(models[indexNow].cmd);
                        }
                    }
                }
            }
            catch(Exception e)
            {
                System.Windows.MessageBox.Show(e.Message);
            }
        }
        #endregion
    }
}
